package com.effectiv.gooruda.rest.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.Path;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import org.springframework.stereotype.Component;

import com.effectiv.gooruda.rest.docs.annotation.Api;
import com.effectiv.gooruda.rest.domain.Session;
import com.effectiv.gooruda.rest.domain.User;
import com.effectiv.gooruda.rest.ext.ExtResponse;
import com.effectiv.gooruda.rest.service.api.SessionService;
import com.effectiv.gooruda.rest.service.api.UserService;

@Path("/session")
@Api(name = "Session API", description = "Session management API.")
@Component
public class SessionServiceImpl extends SessionService {

	@Autowired
	private UserService userService;

	public Response getAttributes(String sessionId) {
		Query query = new Query();
		query.addCriteria(Criteria.where("id").is(sessionId));

		Session s = getTemplate()
				.findOne(query, Session.class, getCollection());

		ExtResponse res = new ExtResponse();
		GenericEntity<ExtResponse> entity = null;
		if (s == null) {
			res.setMessage("No session found for given id - " + sessionId);
		}

		else {
			entity = new GenericEntity<ExtResponse>(res, ExtResponse.class);
			res.setMessage("Session found.");
			res.setValue(s.getAttributes());
		}
		ResponseBuilder builder = Response.ok(entity);

		return builder.build();

	}

	public Response getAttribute(String sessionId, String key) {
		Query query = new Query();
		query.addCriteria(Criteria.where("id").is(sessionId));

		Session s = getTemplate()
				.findOne(query, Session.class, getCollection());

		ExtResponse res = new ExtResponse();
		GenericEntity<ExtResponse> entity = null;
		if (s == null) {
			res.setMessage("No session found for given id - " + sessionId);
		}

		else {
			entity = new GenericEntity<ExtResponse>(res, ExtResponse.class);

			res.setValue(s.getAttributes().get(key));
		}
		ResponseBuilder builder = Response.ok(entity);

		return builder.build();

	}

	public Response findSessionByUser(String userName) {

		Query query = new Query();
		query.addCriteria(Criteria.where("userName").is(userName));

		Session s = getTemplate()
				.findOne(query, Session.class, getCollection());

		ExtResponse res = new ExtResponse();
		GenericEntity<ExtResponse> entity = null;
		if (s == null) {
			res.setMessage("No session found for given user - " + userName);
		}

		else {
			entity = new GenericEntity<ExtResponse>(res, ExtResponse.class);
			res.setValue(s);
		}
		ResponseBuilder builder = Response.ok(entity);

		return builder.build();
	}

	public Response create(String userName) {
		Session s = BeanUtils.instantiate(Session.class);
		s.setAttributes(new HashMap<String, String>());
		s.setUserName(userName);

		getTemplate().save(s, getCollection());

		ExtResponse res = new ExtResponse();
		res.setId(s.getId());
		res.setMessage("Session created successfully.");
		GenericEntity<ExtResponse> entity = new GenericEntity<ExtResponse>(res,
				ExtResponse.class);

		ResponseBuilder builder = Response.ok(entity);

		return builder.build();

	}

	public Session create(User user) {
		Session s = BeanUtils.instantiate(Session.class);
		s.setAttributes(new HashMap<String, String>());
		s.setUserName(user.getUserName());

		getTemplate().save(s, getCollection());
		return s;
	}

	// TODO Optimize
	public Response invalidate(String sessionId) {
		Query query = new Query();
		query.addCriteria(Criteria.where("id").is(sessionId));

		Session s = getTemplate()
				.findOne(query, Session.class, getCollection());

		s.setInvalidatedOn(new Date());

		getTemplate().save(s, getCollection());

		ExtResponse res = new ExtResponse();
		res.setId(sessionId);
		res.setMessage("Session invalidated successfully.");
		GenericEntity<ExtResponse> entity = new GenericEntity<ExtResponse>(res,
				ExtResponse.class);

		ResponseBuilder builder = Response.ok(entity);

		return builder.build();
	}

	public Response removeAllAttributes(String sessionId) {
		Query query = new Query();
		query.addCriteria(Criteria.where("id").is(sessionId));

		Session s = getTemplate()
				.findOne(query, Session.class, getCollection());

		ExtResponse res = new ExtResponse();

		if (s != null) {

			Map<String, String> attributes = s.getAttributes();
			attributes.clear();
			s.setAttributes(attributes);
			getTemplate().save(s, getCollection());

			res.setMessage("All attributes cleared for session id - "
					+ sessionId);
		} else {
			res.setMessage("Session not found for id - " + sessionId);
		}

		GenericEntity<ExtResponse> entity = new GenericEntity<ExtResponse>(res,
				ExtResponse.class);

		ResponseBuilder builder = Response.ok(entity);

		return builder.build();
	}

	public Response removeAttribute(String sessionId, String key) {
		Query query = new Query();
		query.addCriteria(Criteria.where("id").is(sessionId));

		Session s = getTemplate()
				.findOne(query, Session.class, getCollection());

		ExtResponse res = new ExtResponse();

		if (s != null) {

			Map<String, String> attributes = s.getAttributes();

			attributes.remove(key);

			s.setAttributes(attributes);
			getTemplate().save(s, getCollection());

			res.setMessage("Attribute cleared for session id - " + sessionId
					+ " - key - " + key);
		} else {
			res.setMessage("Session not found for id - " + sessionId);
		}
		GenericEntity<ExtResponse> entity = new GenericEntity<ExtResponse>(res,
				ExtResponse.class);

		ResponseBuilder builder = Response.ok(entity);

		return builder.build();
	}

	public Session setAttribute(String sessionId, String key, String value) {
		Query query = new Query();
		query.addCriteria(Criteria.where("id").is(sessionId));

		Session s = getTemplate()
				.findOne(query, Session.class, getCollection());
		Map<String, String> attributes = s.getAttributes();

		attributes.put(key, value);

		s.setAttributes(attributes);
		getTemplate().save(s, getCollection());

		return s;
	}

}
